#include "channel.h"

#include "log.h"

namespace chat {
// ServiceChannel

bool ServiceChannel::append(const std::string& host) {
    // 1. 构造 channel 信道
    brpc::ChannelOptions channel_opts;
    channel_opts.connect_timeout_ms = -1;  // 链接等待超时时间
    channel_opts.timeout_ms = -1;          // 请求等待超时时间
    channel_opts.max_retry = 3;            // 请求重试次数
    channel_opts.protocol = "baidu_std";   // 序列化协议

    ServiceChannel::ChannelPtr channel = std::make_shared<brpc::Channel>();
    int ret = channel->Init(host.c_str(), &channel_opts);
    if (-1 == ret) {
        LOG_ERROR("信道建立失败: {}-{}", service_name_, host);
        return false;
    }

    // 2. 将 channel 信道管理起来
    std::lock_guard<std::mutex> lock(mutex_);

    host_channel_map_.insert({host, channel});
    channels_.push_back(channel);

    return true;
}

bool ServiceChannel::remove(const std::string& host) {
    std::lock_guard<std::mutex> lock(mutex_);

    // 1. 找到 host 对应的 channel
    auto it_host_channel = host_channel_map_.find(host);
    if (it_host_channel == host_channel_map_.end()) {
        LOG_WARN("删除信道时, 服务器中不存在该信道: {}-{}", service_name_,
                 host);
        return false;
    }

    // 2. 从 vector 中删除 channel
    for (auto it_channel = channels_.begin(); it_channel != channels_.end();
         ++it_channel) {
        if (*it_channel == it_host_channel->second) {
            channels_.erase(it_channel);
            break;
        }
    }

    // 3. 从 map 中删除 host-channel
    host_channel_map_.erase(it_host_channel);

    return true;
}

ServiceChannel::ChannelPtr ServiceChannel::choose() {
    std::lock_guard<std::mutex> lock(mutex_);

    if (channels_.empty()) {
        LOG_ERROR("没有节点能够提供服务: {}", service_name_);
        return nullptr;
    }

    index_ %= channels_.size();
    return channels_[index_++];
}

ServiceChannel::ChannelPtr ServiceManager::choose(
    const std::string& service_name) {
    std::lock_guard<std::mutex> lock(mutex_);

    auto it_service = services_.find(service_name);
    if (it_service == services_.end()) {
        LOG_ERROR("没有主机能提供服务: {}", service_name);
        return nullptr;
    }

    return it_service->second->choose();
}

// -------------------------------------------------------------------

// ServiceManager

void ServiceManager::declared(const std::string& service_name) {
    LOG_DEBUG("关心服务: {}", service_name);

    std::lock_guard<std::mutex> lock(mutex_);

    follow_services_.insert(service_name);
}

void ServiceManager::onServiceOnline(const std::string& service_instance,
                                     const std::string& host) {
    const std::string service_name = getServiceName(service_instance);

    // 1. 找到 service_name 的管理类，没有就创建
    ServiceChannelPtr service;
    {
        std::lock_guard<std::mutex> lock(mutex_);

        if (follow_services_.find(service_name) == follow_services_.end()) {
            LOG_DEBUG("{}-{} 上线, 但是并不关心", service_name, host);
            return;
        }

        auto it_service = services_.find(service_name);
        if (it_service == services_.end()) {
            service = std::make_shared<ServiceChannel>();
            services_.insert({service_name, service});
        } else {
            service = it_service->second;
        }
    }

    if (service == nullptr) {
        LOG_ERROR("新增服务失败: {}", service_name);
        return;
    }

    // 2. 将 host 添加到 指定的服务类中
    service->append(host);
}

void ServiceManager::onServiceOffline(const std::string& service_instance,
                                      const std::string& host) {
    const std::string service_name = getServiceName(service_instance);

    // 1. 找到 service_name 的管理类
    ServiceChannelPtr service;
    {
        std::lock_guard<std::mutex> lock(mutex_);

        if (follow_services_.find(service_name) == follow_services_.end()) {
            LOG_DEBUG("{}-{} 下线, 但是并不关心", service_name, host);
            return;
        }

        auto it_service = services_.find(service_name);
        if (it_service == services_.end()) {
            LOG_WARN("要下线的服务不存在: {}", service_name);
            return;
        }
        service = it_service->second;
    }

    // 2. 将 host 从指定的服务类中删除
    service->remove(host);
}

std::string ServiceManager::getServiceName(
    const std::string& service_instance) {
    size_t pos = service_instance.find_last_of('/');
    if (pos == std::string::npos) {
        return service_instance;
    }

    return service_instance.substr(0, pos);
}
}  // namespace chat
